﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Prjinit.Vcses.Core;
using XenoGears.Logging;
using XenoGears.Functional;
using XenoGears.Logging.Formatters;

namespace Prjinit.Vcses
{
    [Vcs("hg", "mercurial"), Default]
    internal class Mercurial : Vcs
    {
        public override void Bootstrap()
        {
            if (!Cfg.TargetDir.Exists)
            {
                Cfg.TargetDir.Create();
            }

            hg("init");

            if (Cfg.VcsRepo.IsNeitherNullNorEmpty())
            {
                // todo. to be implemented
                throw new Exception("Mercurial bootstrapper doesn't yet support explicit VCS repos.");
            }
        }

        public override void Commit(String message)
        {
            hg("addremove");
            hg("commit -m \"{0}\"", message);
        }

        private void hg(String format, params String[] args)
        {
            if (hgexe == null) throw new Exception("Fatal error: cannot find hg.exe!");
            var psi = new ProcessStartInfo(hgexe);
            psi.Arguments = String.Format(format, args);
            psi.WorkingDirectory = Cfg.TargetDir.FullName;
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.CreateNoWindow = true;

            Debug.EnsureBlankLine();
            Debug.WriteLine("Launching \"hg.exe {0}\"...", psi.Arguments);
            var p = Process.Start(psi);
            if (p == null) throw new Exception(String.Format("Fatal error: failed to lauch \"hg.exe {0}\"!", psi.Arguments));
            var stdout = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            Debug.WriteLine("\"hg.exe {0}\" has completed execution.", psi.Arguments);
            Debug.WriteLine("\"hg.exe {0}\" has produced the following output:", psi.Arguments);
            Debug.WriteLine(stdout.ToLog());
        }

        private bool _hgexe_cached = false;
        private String _hgexe = null;
        private String hgexe
        {
            get
            {
                if (!_hgexe_cached)
                {
                    try
                    {
                        var var_path = Environment.GetEnvironmentVariable("PATH") ?? String.Empty;
                        Debug.WriteLine("Detecting path to hg.exe...");
                        Debug.WriteLine("PATH is {0}...", var_path.ToLog());

                        var paths = var_path.Split(Path.PathSeparator).Select(s => s.Trim()).ToArray();
                        foreach (var path in paths)
                        {
                            var dir = path;
                            if (!dir.EndsWith(Path.DirectorySeparatorChar.ToString()))
                                dir += Path.DirectorySeparatorChar.ToString();
                            var hgexe = dir + "hg.exe";

                            Debug.WriteLine("Checking at {0}...", hgexe.ToLog());
                            if (File.Exists(hgexe))
                            {
                                Debug.WriteLine("Successfully found hg.exe at {0}...", hgexe.ToLog());
                                _hgexe = hgexe;
                                return _hgexe;
                            }
                        }

                        Error.EnsureBlankLine();
                        Error.WriteLine("Cannot find hg.exe in PATH, which is:" + (paths.Count() > 0 ? "" : "<empty>"));
                        foreach (var path in paths) Error.WriteLine(path.ToLog());

                        Error.EnsureBlankLine();
                        Error.WriteLine("Please, install TortoiseHg (btw it's free) ");
                        Error.WriteLine("and then register path to hg.exe in the PATH environment variable");
                        Error.WriteLine("(hg.exe usually resides under \"%INSTALL_DIR%\\hg.exe\")");
                    }
                    finally 
                    {
                        _hgexe_cached = true;
                    }
                }

                return _hgexe;
            }
        }
    }
}
